今天這篇文章要來介紹另外兩個hooks,useCallback和useMemo兩個都是用來效能優化的hooks,用法相當類似,都是藉由快取來達到優化的效果。
const cachedFn = useCallback(fn, dependencies)
useCallback會需要帶入兩個參數,第一個是function,第二個是相依的變數,然後在第一次元件渲染回傳帶入的第一個參數的function,之後如果相依的變數有變更的時候才會再回傳新的function。這個相依變數有變更,是用Object.is()來進行比較,也就是說如果是物件、陣列或是函式,要是相同的記憶體位置才會被視為相同的。以下是官網給的一個範例,看了範例可能可以更好懂一點,如果productId或是referrer有變更的時候useCallback就會回傳當下渲染的function,如果沒有改變就會回傳第一次渲染的function。在這邊React的作法其實每次渲染的時候還是會產生一個新的function,但如果相依變數沒有變更,就會忽略這個新產生的function,回傳快取的function。
import { useCallback } from 'react';
export default function ProductPage({ productId, referrer, theme }) {
const handleSubmit = useCallback((orderDetails) => {
post('/product/' + productId + '/buy', {
referrer,
orderDetails,
});
}, [productId, referrer]);
const cachedValue = useMemo(calculateValue, dependencies)
與useCallback非常類似,一樣帶入兩個function,第一個是function,第二個是相依的變數,差別在於useCallback會回傳整個function,useMemo則是回傳function執行過後的結果。第一次渲染的時候會執行一次帶入的function,再來如果相依變數有變更才會重新執行一次function,不然就會回傳之前執行function快取的值。適用於運算很複雜的情境。
import { useMemo } from 'react';
function TodoList({ todos, tab }) {
const visibleTodos = useMemo(
() => filterTodos(todos, tab),
[todos, tab]
);
// ...
}
如果只是一般的網站,沒什麼太多的互動,其實也沒有必要使用這些hook來優化,優化效果可能也是有限的。以下官方文件有提到的兩個可能可以使用的情境。
因為我主要是使用air bnb的eslint style,它都會要求使用useMemo。雖然官網文件有說即使所有內容都使用useMemo和useCallback對網頁效能也不會有太明顯的傷害,但是對於code的可讀性可能會變差,對於相依變數每次都會變更的使用這兩個hooks也是沒有必要的。所以綜合以上我將來的使用可能還是會有所節制,畢竟很多時候加上去雖然沒什麼壞處,但是也沒有好處,反而徒增code變得更難維護與閱讀。
https://react.dev/reference/react/useCallback
https://react.dev/reference/react/useMemo